package com.leenmvc.core.config.filter;

import com.leenmvc.core.base.BaseEntity;
import com.leenmvc.core.base.EntityInfo;
import com.leenmvc.core.cache.CacheFactory;
import com.leenmvc.core.enums.CacheType;
import com.leenmvc.core.init.Constant;
import com.leenmvc.core.security.User;
import com.leenmvc.core.security.dao.core.SysPermissionDao;
import com.leenmvc.core.security.entity.core.SysPermission;
import com.leenmvc.core.utils.ClassUtil;
import com.leenmvc.core.utils.TipUtil;
import com.leenmvc.core.utils.http.HttpContextUtils;
import com.leenmvc.core.utils.http.RequestParameterWrapper;
import com.leenmvc.core.utils.http.entity.UrlData;
import com.leenmvc.core.utils.spring.SpringContextUtils;
import com.leenmvc.core.utils.thread.ThreadLocalManager;
import com.sun.xml.bind.v2.runtime.reflect.opt.Const;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 全局过滤器
 */
@WebFilter(filterName = "myFilter", urlPatterns = "/*")
public class GlobalFilter implements Filter {

    private final static Logger logger = LoggerFactory.getLogger(GlobalFilter.class);

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        try {
            // 根据 url 转向
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponseWrapper httpResponse = new HttpServletResponseWrapper((HttpServletResponse) response);
            String path = httpRequest.getRequestURI();
            logger.info("本次请求的请求地址是：{}", path);
            // 设置实际url本地变量(只能在这里设置，在过滤器中设置那么永远都会是公共方法)
            ThreadLocalManager.put("uri", path);
            ThreadLocalManager.put("contentType", request.getContentType());
            // 删除
            String method = httpRequest.getMethod();

            String[] pathArr = path.split("/");
            if (BaseEntity.entityMap.get(pathArr[pathArr.length - 1]) != null) {
                EntityInfo entity = BaseEntity.entityMap.get(pathArr[pathArr.length - 1]);
                String tableComment = ClassUtil.getTableComment(entity.getRealClass());
                ThreadLocalManager.put("module", tableComment);
                if ("delete".equalsIgnoreCase(method)) {
                    authentication(httpRequest, httpResponse, pathArr, "del", 1);
                    logger.info("过滤器执行转发转发地址为/system/common/的删除操作；实际对象url为：{}", path);
                    ThreadLocalManager.put("note", "根据ID数组删除" + tableComment);
                    httpRequest.getRequestDispatcher("/system/common").forward(getRequestParameterWrapper(httpRequest, path), response);
                    return;
                } else if ("post".equalsIgnoreCase(method)) {
                    authentication(httpRequest, httpResponse, pathArr, "save", 1);
                    logger.info("过滤器执行转发转发地址为/system/common/的保存操作；实际对象url为：", path);
                    ThreadLocalManager.put("note", "新增" + tableComment + "记录");
                    httpRequest.getRequestDispatcher("/system/common").forward(getRequestParameterWrapper(httpRequest, path), response);
                    return;
                } else if ("put".equalsIgnoreCase(method)) {
                    authentication(httpRequest, httpResponse, pathArr, "update", 1);
                    logger.info("过滤器执行转发转发地址为/system/common/的更新操作；实际对象url为：", path);
                    ThreadLocalManager.put("note", "修改" + tableComment + "记录");
                    httpRequest.getRequestDispatcher("/system/common").forward(getRequestParameterWrapper(httpRequest, path), response);
                    return;
                }
            }
            EntityInfo entityInfo = BaseEntity.entityMap.get(pathArr[pathArr.length - 2]);
            String tableComment = "";
            if (entityInfo != null) {
                tableComment = ClassUtil.getTableComment(entityInfo.getRealClass());
                ThreadLocalManager.put("module", tableComment);
            }

            if (path.endsWith("/page")) {
                authentication(httpRequest, httpResponse, pathArr, "page", 2);
                ThreadLocalManager.put("note", "分页获取" + tableComment + "记录");
                logger.info("[公用获取分页记录方法]过滤器执行转发转发地址为/system/common/page");
                httpRequest.getRequestDispatcher("/system/common/page").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith("/sqlPage")) {
                authentication(httpRequest, httpResponse, pathArr, "sqlPage", 2);
                ThreadLocalManager.put("note", "分页获取" + tableComment + "记录（手写SQL语句）");
                logger.info("[公用获取分页记录方法]过滤器执行转发转发地址为/system/common/sqlPage");
                httpRequest.getRequestDispatcher("/system/common/sqlPage").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith("/sqlKvs")) {
                authentication(httpRequest, httpResponse, pathArr, "sqlKvs", 2);
                ThreadLocalManager.put("note", "获取" + tableComment + "的KVs键值对记录(手写SQL)");
                logger.info("[公用获取KVS手写SQL记录方法]过滤器执行转发转发地址为/system/common/sqlKvs");
                httpRequest.getRequestDispatcher("/system/common/sqlKvs").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith("/kvs")) {
                authentication(httpRequest, httpResponse, pathArr, "kvs", 2);
                ThreadLocalManager.put("note", "获取" + tableComment + "的KVs键值对记录");
                logger.info("[公用获取KVS记录方法]过滤器执行转发转发地址为/system/common/kvs");
                httpRequest.getRequestDispatcher("/system/common/kvs").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith("/getById")) {
                authentication(httpRequest, httpResponse, pathArr, "getById", 2);
                ThreadLocalManager.put("note", "根据ID获取" + tableComment + "记录");
                logger.info("[公用根据ID获取单条记录方法]过滤器执行转发转发地址为/system/common/getById");
                httpRequest.getRequestDispatcher("/system/common/getById").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            }  else if (path.endsWith("/getList")) {
                authentication(httpRequest, httpResponse, pathArr, "getList", 2);
                ThreadLocalManager.put("note", "根据ID获取" + tableComment + "记录");
                logger.info("[公用获取列表]过滤器执行转发转发地址为/system/common/getList");
                httpRequest.getRequestDispatcher("/system/common/getList").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith("/getAll")) {
                authentication(httpRequest, httpResponse, pathArr, "getAll", 2);
                ThreadLocalManager.put("note", "根据ID获取" + tableComment + "记录");
                logger.info("[公用获取全部记录]过滤器执行转发转发地址为/system/common/getAll");
                httpRequest.getRequestDispatcher("/system/common/getAll").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if(path.endsWith("/simpleExport")) {
                authentication(httpRequest, httpResponse, pathArr, "export", 2);
                ThreadLocalManager.put("note", "导出数据表为Excel表格（" + tableComment + ")");
                logger.info("[公用方法导出]过滤器执行转发转发地址为/system/common/export");
                httpRequest.getRequestDispatcher("/system/common/export").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            }
            else {
                logger.info("过滤器正式执行过滤通过操作，通过路径为：{}, 该请求携带的参数为：{}", path, HttpContextUtils.getParameterMap(httpRequest));
                UrlData urlData = CacheFactory.get(CacheType.URL_INFO, path);
                ThreadLocalManager.put("module", urlData == null ? "未指定模块" : urlData.getModule());
                chain.doFilter(request, response);
                return;
            }
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } catch (ServletException e) {
            logger.error(e.getMessage(), e);
        }

    }

    /**
     * 公共方法鉴权
     *
     * @param pathArr
     */
    private void authentication(HttpServletRequest httpRequest, HttpServletResponseWrapper httpResponse, String[] pathArr, String authentication, int index) {
        if(Constant.dev_mode) return;
        Integer superAdmin = User.getSuperAdmin();
        logger.info("当前用户是否为超级管理员对象: {}" , superAdmin);
        if(superAdmin != null && superAdmin == 1) {
            return;
        }

        Set<String> permisions = User.getPermisions();
        String auth = pathArr[pathArr.length - (index + 1)] + ":" + pathArr[pathArr.length - index] + ":" + authentication;
        if (!permisions.contains(auth)) {
            SysPermissionDao sysPermissionDao = SpringContextUtils.getBean(SysPermissionDao.class);
            SysPermission perm = sysPermissionDao.get("identification", auth);
            if (perm == null) {
                HttpContextUtils.returnJSON(httpRequest, httpResponse, TipUtil.getTip("EXCEPTION_POWER_NOT_OPEN", auth));
                return;
            }
            HttpContextUtils.returnJSON(httpRequest, httpResponse, TipUtil.getTip("EXCEPTION_NO_POWER", perm.getModule(), perm.getName(), perm.getIdentification()));
        }
    }

    private RequestParameterWrapper getRequestParameterWrapper(HttpServletRequest httpRequest, String path) {
        Map<String, Object> otherParams = new HashMap<>();
        otherParams.put("url", path);
        RequestParameterWrapper requestParameterWrapper = new RequestParameterWrapper(httpRequest);
        requestParameterWrapper.addParameters(otherParams);
        ThreadLocalManager.put("request_url", path);
        return requestParameterWrapper;
    }

    @Override
    public void destroy() {
    }
}
